import xml.etree.ElementTree as ET
import os
import time
import shutil
import re
import json
import requests
import logging
import subprocess
import threading
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import queue
from get_kodi_info import get_kodi_credentials, kodi_jsonrpc
from parse_playlist import get_playlist_items
from download_posters import extract_and_save_posters
from generate_poster import generate_poster

os.chdir(os.path.dirname(os.path.abspath(__file__)))

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("gen_poster")

# Kodi收藏文件路径配置
POSSIBLE_FAVOURITES_PATHS = [
    "/storage/.kodi/userdata/favourites.xml",  # 默认路径
    "/home/osmc/.kodi/userdata/favourites.xml",  # OSMC系统路径
    "/root/.kodi/userdata/favourites.xml",  # 根用户路径
    "/kodi/userdata/favourites.xml"  # 容器环境路径
]

# 尝试找到实际存在的收藏文件路径
FAVOURITES_XML_PATH = None
for path in POSSIBLE_FAVOURITES_PATHS:
    if os.path.exists(path):
        FAVOURITES_XML_PATH = path
        logger.info(f"找到Kodi收藏文件: {FAVOURITES_XML_PATH}")
        break

if not FAVOURITES_XML_PATH:
    logger.warning("未找到Kodi收藏文件，将使用默认路径")
    FAVOURITES_XML_PATH = POSSIBLE_FAVOURITES_PATHS[0]

DATA_FOLDER = "data"
TEMP_FOLDER = "temp"
OUTPUT_FOLDER = "output"  # 封面统一保存路径

os.makedirs(DATA_FOLDER, exist_ok=True)
os.makedirs(TEMP_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)

# 全局变量
is_main_running = False
main_lock = threading.Lock()
change_event_queue = queue.Queue()
last_processed_mtime = 0

def translate_text(text):
    """使用翻译接口翻译文本并提取实际翻译内容"""
    url = f"https://translate.appworlds.cn/?text={text}&from=zh-CN&to=en"
    try:
        response = requests.get(url)
        response.raise_for_status()

        # 解析JSON响应
        result = response.json()

        # 提取实际翻译内容
        if result.get("code") == 200 and "data" in result:
            translation = result["data"]
            # 去除特殊符号
            translation = re.sub(r'[^\w\s]', '', translation)
            return translation
        else:
            print(f"翻译接口返回异常: {result}")
            return text  # 翻译失败时返回原文

    except (requests.RequestException, ValueError) as e:
        print(f"翻译请求失败: {e}")
        return text  # 发生异常时返回原文


def get_media_count(playlist_items):
    """统计媒体类型的数量"""
    media_types = {
        "movies": 0,
        "tvshows": 0,
        "episodes": 0,
        "songs": 0
    }
    for item in playlist_items:
        if "showtitle" in item:
            media_types["episodes"] += 1
        elif "artist" in item:
            media_types["songs"] += 1
        elif "year" in item:
            media_types["movies"] += 1
        elif "title" in item:
            media_types["tvshows"] += 1
    return media_types

def update_favourites_xml(favourites_xml_path, name, thumb_path):
    """更新favourites.xml中对应name的thumb路径，使用绝对路径"""
    print(f"封面绝对路径: {thumb_path}")
    
    # 解析XML文件
    try:
        tree = ET.parse(favourites_xml_path)
        root = tree.getroot()
    except FileNotFoundError:
        print(f"错误: 文件 {favourites_xml_path} 不存在")
        return False
    except Exception as e:
        print(f"解析XML文件时出错: {e}")
        return False
    
    # 查找并更新对应的收藏项
    updated = False
    for favourite in root.findall('favourite'):
        if favourite.get('name') == name:
            print(f"更新 {name} 的封面路径为: {thumb_path}")
            favourite.set('thumb', thumb_path)
            updated = True
    
    if not updated:
        print(f"警告: 未找到名为 '{name}' 的收藏项")
    
    # 保存更新后的XML文件，指定编码为UTF-8
    try:
        # 创建备份文件
        backup_path = favourites_xml_path + ".bak"
        tree.write(backup_path, encoding='utf-8', xml_declaration=True)
        
        # 添加XML声明并写入新文件
        with open(favourites_xml_path, 'w', encoding='utf-8') as f:
            f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
            tree.write(f, encoding='unicode')
            
        print(f"已成功更新 {favourites_xml_path}")
        return True
    except Exception as e:
        print(f"保存XML文件时出错: {e}")
        return False

def kodi_jsonrpc(method, params, credentials):
    """发送JRPC请求到Kodi"""
    url = f"http://{credentials['host']}:{credentials['port']}/jsonrpc"
    payload = {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "id": 1
    }
    
    if credentials.get("username") and credentials.get("password"):
        auth = (credentials["username"], credentials["password"])
    else:
        auth = None
    
    try:
        response = requests.post(url, json=payload, auth=auth, timeout=10)
        response.raise_for_status()
        return response.json()
    except requests.RequestException as e:
        print(f"JRPC请求失败: {e}")
        return None

def extract_playlist_path(favourite):
    """从favourite节点中提取播放列表路径，返回本地路径和原始special路径"""
    cmd = favourite.text or ""
    original_path = None
    
    # 提取原始special路径
    if "playplaylist" in cmd.lower() or "activatewindow" in cmd.lower():
        start = cmd.find('"') + 1
        end = cmd.find('"', start)
        if start > 0 and end > start:
            original_path = cmd[start:end].strip()
    
    if not original_path:
        # 尝试从属性中获取
        for attr in ["file", "path", "filename"]:
            original_path = favourite.get(attr)
            if original_path and original_path.startswith("special://"):
                break
    
    if not original_path:
        return None, None
    
    # 转换为本地路径
    local_path = original_path
    if local_path.startswith("special://profile/"):
        local_path = local_path.replace("special://profile/", "/storage/.kodi/userdata/")
    elif local_path.startswith("special://home/"):
        local_path = local_path.replace("special://home/", "/storage/.kodi/")
    elif local_path.startswith("special://videoplaylists/"):
        local_path = local_path.replace("special://videoplaylists/", "/storage/.kodi/userdata/playlists/video/")
    elif local_path.startswith("special://musicplaylists/"):
        local_path = local_path.replace("special://musicplaylists/", "/storage/.kodi/userdata/playlists/music/")
    
    return local_path, original_path

def update_favourite_via_jrpc(credentials, name, original_path, new_thumb):
    """通过JRPC更新收藏项的thumb，使用原始special路径"""
    get_response = kodi_jsonrpc("Favourites.GetFavourites", {"properties": ["type", "path"]}, credentials)
    if not get_response or "result" not in get_response or "favourites" not in get_response["result"]:
        print(f"❌ 无法获取收藏项列表")
        return False
    
    # 查找包含原始路径的收藏项
    target_fav = None
    for fav in get_response["result"]["favourites"]:
        if fav["title"] == name and original_path in fav["path"]:
            target_fav = fav
            break
    
    if not target_fav:
        print(f"⚠️ 未找到收藏项: {name} (原始路径: {original_path})")
        return False
    
    # 使用原始完整路径（如ActivateWindow(10025,"special://...")）
    update_params = {
        "type": target_fav["type"],
        "title": name,
        "path": target_fav["path"],
        "thumbnail": new_thumb
    }
    
    add_response = kodi_jsonrpc("Favourites.AddFavourite", update_params, credentials)
    return add_response and add_response.get("result") == "OK"

def send_kodi_notification(credentials, title, message):
    """通过JSON-RPC向Kodi发送通知"""
    try:
        params = {
            "title": title,
            "message": message
        }
        kodi_jsonrpc('GUI.ShowNotification', params, credentials)
        print(f"✅ 已向Kodi发送通知: {title} - {message}")
    except Exception as e:
        print(f"⚠️ 发送Kodi通知失败: {e}")

def main():
    global last_processed_mtime
    
    # 检查文件是否存在
    if not os.path.exists(FAVOURITES_XML_PATH):
        logger.warning(f"收藏文件 {FAVOURITES_XML_PATH} 不存在，跳过处理")
        return
    
    start_mtime = os.path.getmtime(FAVOURITES_XML_PATH)
    logger.info(f"开始处理文件变更 (mtime: {start_mtime})")
    
    def check_file_changed():
        # 检查文件是否存在及修改时间
        if not os.path.exists(FAVOURITES_XML_PATH):
            logger.warning(f"收藏文件 {FAVOURITES_XML_PATH} 在处理期间被删除")
            return True
            
        current_mtime = os.path.getmtime(FAVOURITES_XML_PATH)
        if current_mtime != start_mtime:
            logger.warning(f"文件在处理期间被再次修改 (新mtime: {current_mtime})")
            return True
        return False
    
    print("==== 开始自动生成封面 ====")
    credentials = get_kodi_credentials()
    print(f"✅ Kodi认证信息: {credentials}")
    
    try:
        tree = ET.parse(FAVOURITES_XML_PATH)
        root = tree.getroot()
        print(f"✅ 成功解析 {FAVOURITES_XML_PATH}")
    except FileNotFoundError:
        print(f"文件在解析过程中被删除: {FAVOURITES_XML_PATH}")
        return
    except Exception as e:
        print(f"❌ 解析favourites.xml失败: {e}")
        return
    
    total_favourites = len(root.findall('favourite'))
    print(f"发现 {total_favourites} 个收藏项")
    
    processed_count = 0
    generated_count = 0
    updated_count = 0
    
    for index, favourite in enumerate(root.findall('favourite')):
        if index % 5 == 0 and check_file_changed():
            logger.warning("检测到文件变更，终止当前处理")
            return
        
        name = favourite.get('name')
        if not name:
            print(f"⚠️ 收藏项 #{index+1} 没有名称，跳过")
            continue
        
        # 获取本地路径和原始路径
        playlist_path, original_path = extract_playlist_path(favourite)
        
        if not playlist_path or not original_path:
            print("⚠️ 未找到有效播放列表路径，跳过")
            continue
        
        print(f"处理收藏项: {name}")
        print(f"🔍 播放列表原始路径: {original_path}")
        print(f"🔍 播放列表本地路径: {playlist_path}")
        
        # 检查文件是否存在
        if not os.path.exists(playlist_path):
            print(f"❌ 播放列表文件不存在: {playlist_path}")
            continue
        
        data_file_path = os.path.join(DATA_FOLDER, f"{name}.json")
        if os.path.exists(data_file_path):
            with open(data_file_path, 'r', encoding='utf-8') as f:
                prev_data = json.load(f)
            print(f"✅ 找到历史数据: {data_file_path}")
        else:
            prev_data = {}
            print("ℹ️ 没有历史数据，将创建新数据")
        
        print("🔍 获取播放列表内容...")
        playlist_items = get_playlist_items(playlist_path, credentials)
        if not playlist_items:
            print("❌ 未找到媒体项，跳过")
            continue
        
        processed_count += 1
        media_count = get_media_count(playlist_items)
        print(f"📊 媒体统计: {media_count}")
        
        # 检查是否需要更新
        if media_count == prev_data.get('media_count', {}):
            print(f"✅ {name} 的媒体数量未改变，跳过更新")
            continue
        
        subtitle = translate_text(name)
        logger.info(f"翻译结果: 中文名称='{name}', 英文副标题='{subtitle}'")

        new_data = {
            "media_count": media_count,
            "subtitle": subtitle
        }

        with open(data_file_path, 'w', encoding='utf-8') as f:
            json.dump(new_data, f, ensure_ascii=False, indent=4)
        print(f"💾 已保存统计数据到: {data_file_path}")
        
        # 清理并准备临时文件夹
        shutil.rmtree(TEMP_FOLDER, ignore_errors=True)
        os.makedirs(TEMP_FOLDER)
        
        # 决定下载数量
        if sum(media_count.values()) >= 9:
            selected_items = playlist_items[:9]
        else:
            selected_items = playlist_items
        
        print(f"📥 准备下载 {len(selected_items)} 张海报")
        success_count = extract_and_save_posters(selected_items, TEMP_FOLDER)
        print(f"✅ 成功下载 {success_count} 张海报")
        
        if success_count > 0:
            poster_name = f"{name}.png"
            poster_path = os.path.join(OUTPUT_FOLDER, poster_name)  # 使用配置的输出路径
            print(f"🎨 生成封面: {poster_name}")
            
            # 生成海报
            result = generate_poster(title=name, subtitle=new_data["subtitle"], output_filename=poster_path)
            if result:
                absolute_poster_path = os.path.abspath(poster_path)  # 获取绝对路径
                print(f"✅ 封面已生成: {absolute_poster_path}")
                generated_count += 1
                
                # 通过JRPC更新收藏项（使用原始路径）
                update_result = update_favourite_via_jrpc(credentials, name, original_path, absolute_poster_path)
                if update_result:
                    updated_count += 1
                    
                    # 发送Kodi通知
                    send_kodi_notification(credentials, "封面更新", f"{name} 的封面已更新")
                else:
                    print("❌ 通过JRPC更新失败，尝试回退到XML更新")
                    # 回退到XML更新作为备选方案
                    update_favourites_xml(FAVOURITES_XML_PATH, name, absolute_poster_path)
            else:
                print("❌ 封面生成失败")
        else:
            print(f"❌ 没有可用的海报，跳过封面生成")
        
        # 清理临时文件夹
        shutil.rmtree(TEMP_FOLDER, ignore_errors=True)
        os.makedirs(TEMP_FOLDER)
    
    print(f"\n==== 处理完成 ====")
    print(f"总收藏项: {total_favourites}")
    print(f"处理的收藏项: {processed_count}")
    print(f"生成的封面数: {generated_count}")
    print(f"更新的收藏项: {updated_count}")
    
    # 移除重启Kodi的逻辑
    # if generated_count > 0 and updated_count > 0:
    #     print("\n🔄 重启Kodi以应用更改...")
    #     restart_kodi()

def extract_playlist_path(favourite):
    """从favourite节点中提取播放列表路径，返回本地路径和原始special路径"""
    cmd = favourite.text or ""
    original_path = None
    
    # 提取原始special路径
    if "playplaylist" in cmd.lower() or "activatewindow" in cmd.lower():
        start = cmd.find('"') + 1
        end = cmd.find('"', start)
        if start > 0 and end > start:
            original_path = cmd[start:end].strip()
    
    if not original_path:
        # 尝试从属性中获取
        for attr in ["file", "path", "filename"]:
            original_path = favourite.get(attr)
            if original_path and original_path.startswith("special://"):
                break
    
    if not original_path:
        return None, None
    
    # 转换为本地路径
    local_path = original_path
    if local_path.startswith("special://profile/"):
        local_path = local_path.replace("special://profile/", "/storage/.kodi/userdata/")
    elif local_path.startswith("special://home/"):
        local_path = local_path.replace("special://home/", "/storage/.kodi/")
    elif local_path.startswith("special://videoplaylists/"):
        local_path = local_path.replace("special://videoplaylists/", "/storage/.kodi/userdata/playlists/video/")
    elif local_path.startswith("special://musicplaylists/"):
        local_path = local_path.replace("special://musicplaylists/", "/storage/.kodi/userdata/playlists/music/")
    
    return local_path, original_path

class FavouritesHandler(FileSystemEventHandler):
    def on_modified(self, event):
        global change_event_queue
        
        if not event.is_directory and event.src_path.endswith(os.path.basename(FAVOURITES_XML_PATH)):
            try:
                # 检查文件是否存在（可能被删除后又创建）
                if not os.path.exists(FAVOURITES_XML_PATH):
                    logger.warning(f"收藏文件 {FAVOURITES_XML_PATH} 不存在，跳过处理")
                    return
                
                current_mtime = os.path.getmtime(FAVOURITES_XML_PATH)
                logger.info(f"检测到文件更新 (mtime: {current_mtime}): {event.src_path}")
                
                change_event_queue.put(current_mtime)
                process_change_event()
            except Exception as e:
                logger.error(f"处理文件变更事件失败: {e}")

def process_change_event():
    global is_main_running, last_processed_mtime
    
    with main_lock:
        if is_main_running:
            logger.info("main函数正在执行中，变更事件将在执行完成后处理")
            return
        
        if change_event_queue.empty():
            return
        
        latest_mtime = change_event_queue.queue[-1]
        
        while not change_event_queue.empty():
            change_event_queue.get()
        
        if latest_mtime == last_processed_mtime:
            logger.info("文件修改时间未变，跳过处理")
            return
        
        # 检查文件是否仍然存在
        if not os.path.exists(FAVOURITES_XML_PATH):
            logger.warning(f"收藏文件 {FAVOURITES_XML_PATH} 不存在，跳过处理")
            return
        
        is_main_running = True
        last_processed_mtime = latest_mtime
    
    try:
        logger.info("启动main函数处理文件变更...")
        start_time = time.time()
        main()
        exec_time = time.time() - start_time
        logger.info(f"✅ main函数执行完成，耗时 {exec_time:.2f} 秒")
        
        process_change_event()
    except Exception as e:
        logger.error(f"❌ main函数执行出错: {e}")
    finally:
        with main_lock:
            is_main_running = False

def start_watcher():
    event_handler = FavouritesHandler()
    observer = Observer()
    
    # 检查目录是否存在
    dir_path = os.path.dirname(FAVOURITES_XML_PATH)
    if not os.path.exists(dir_path):
        logger.warning(f"监控目录不存在: {dir_path}，创建目录")
        os.makedirs(dir_path, exist_ok=True)
    
    observer.schedule(event_handler, path=dir_path, recursive=False)
    observer.start()
    logger.info(f"开始监控 {FAVOURITES_XML_PATH} 文件变化...")
    
    try:
        while True:
            time.sleep(5)
    except KeyboardInterrupt:
        logger.info("程序被用户中断，停止监控...")
        observer.stop()
    observer.join()

if __name__ == "__main__":
    logger.info("首次启动程序...")
    
    # 如果收藏文件存在，执行一次main
    if os.path.exists(FAVOURITES_XML_PATH):
        logger.info("收藏文件存在，执行初始处理")
        main()
    else:
        logger.info("收藏文件不存在，等待创建")
    
    # 启动文件监控
    start_watcher()
